package gogo

import (
	"net/http"
	"strconv"

	"github.com/gorilla/websocket"
)

var (
	upgrader = websocket.Upgrader{
		// 读取存储空间大小
		ReadBufferSize: 1024,
		// 写入存储空间大小
		WriteBufferSize: 1024,
		// 允许跨域
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
)

var (
	ImplConnMap map[string]*ImplConnection
)

func CloseConn(wsConn *websocket.Conn, conn *ImplConnection) {
	if wsConn != nil {
		wsConn.Close()
	} else if conn != nil {
		delete(ImplConnMap, conn.RemoteAddr().String())
		conn.Close()
	}
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	var (
		wsConn *websocket.Conn = nil
		err    error
		conn   *ImplConnection = nil
		data   []byte
	)
	// 完成http应答，在httpheader中放下如下参数
	if wsConn, err = upgrader.Upgrade(w, r, nil); err != nil {
		goto ERR
	}

	if conn, err = InitImplConnection(wsConn); err != nil {
		goto ERR
	}

	ImplConnMap[conn.RemoteAddr().String()] = conn

	go func() {
		for {
			// 每隔一秒发送一次心跳
			if err := conn.WriteMessage([]byte("iamok")); err != nil {
				Log().DebugF("heartbeat error: %s", err.Error())
				CloseConn(wsConn, conn)
				return
			}
			Utils().TimeSleepSecond(1)
		}
	}()

	for {
		if data, err = conn.ReadMessage(); err != nil {
			goto ERR
		}

		if ProcHandle != nil {
			b, err := ProcHandle(data, conn)

			if err != nil {
				goto ERR

			} else if b != nil {
				conn.WriteMessage(b)
			}
		}
	}

ERR:
	if err != nil {
		Log().DebugF("wsHandler error: %s", err.Error())
	}
	CloseConn(wsConn, conn)
}

// WebSocketSendToAll 向所有连接的websocket客户端发送消息
// b byte[]格式的消息内容
func WebSocketSendToAll(b []byte) {
	for addr := range ImplConnMap {
		ImplConnMap[addr].WriteMessage(b)
	}
}

// WebSocketSendToGroup 向指定分组的websocket客户端发送消息，分组通过WebSocketSetGroup函数接口设置
// b byte[]格式的消息内容
// group 分组名称
func WebSocketSendToGroup(b []byte, groupName string) {
	for addr := range ImplConnMap {
		conn := ImplConnMap[addr]
		if conn.GetGroup() == groupName {
			conn.WriteMessage(b)
		}
	}
}

// ProcHandle 开发者注册的回调函数，初始化为nil，在RunWebSocket函数中会赋值
// []byte 接收到的内容
// *ImplConnection 发送接口指针，可用此指针回复相应客户端
var ProcHandle func([]byte, *ImplConnection) ([]byte, error)

// StartWebSocket 启动websocket服务
// pattern 服务路径
// port 端口号
// handler 注册回调函数
func StartWebSocket(pattern string, port int, handler func([]byte, *ImplConnection) ([]byte, error)) error {
	ImplConnMap = make(map[string]*ImplConnection)

	ProcHandle = handler

	// 当有请求访问pattern时，执行此回调方法
	http.HandleFunc(pattern, wsHandler)

	// 监听addr
	addr := ":" + strconv.Itoa(port)
	Log().Info("WebSocket Service Running on ", addr)
	return http.ListenAndServe(addr, nil)
}
